package com.neusoft.bizcore.auth.service.impl;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.neusoft.bizcore.auth.converter.DingConfigConverter;
import com.neusoft.bizcore.auth.dto.DingConfigDTO;
import com.neusoft.bizcore.auth.model.AuthUser;
import com.neusoft.bizcore.auth.model.DingConfig;
import com.neusoft.bizcore.auth.model.DingUser;
import com.neusoft.bizcore.auth.repository.AuthUserRepository;
import com.neusoft.bizcore.auth.repository.DingConfigRepository;
import com.neusoft.bizcore.auth.repository.DingUserRepository;
import com.neusoft.bizcore.auth.service.DingDingService;
import com.neusoft.bizcore.web.utils.JsonUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class DingDingServiceImpl implements DingDingService {

    public final static String DING_OPEN_API_BASE_URL = "https://oapi.dingtalk.com";
    public final static String DING_GET_TOKEN_URL = "/gettoken?appkey=%s&appsecret=%s";
    public final static String DING_GET_USER_INRO_URL = "/user/getuserinfo?access_token=%s&code=%s";

    @Autowired
    private DingConfigRepository dingConfigRepository;
    @Autowired
    private DingConfigConverter dingConfigConverter;
    @Autowired
    private AuthUserRepository authUserRepository;
    @Autowired
    private DingUserRepository dingUserRepository;
    @Autowired
    private RestTemplate restTemplate;

    @Override
    public DingConfigDTO getDingConfig() {
        final List<DingConfig> list = this.dingConfigRepository.findAll();
        if (list.size() > 0) {
            return this.dingConfigConverter.toDTO(list.get(0));
        }
        return null;
    }

    @Override
    public DingConfigDTO setDingConfig(final DingConfigDTO dto) {
        DingConfig model = this.dingConfigConverter.toModel(dto);
        if (model.isNew()) {
            final List<DingConfig> list = this.dingConfigRepository.findAll();
            if (list.size() > 0) {
                return this.dingConfigConverter.toDTO(list.get(0));
            }
        }
        model = this.dingConfigRepository.save(model);
        return this.dingConfigConverter.toDTO(model);
    }

    @Override
    public void delete(final long id) {
        this.dingConfigRepository.deleteById(id);

    }

    /**
     * https://ding-doc.dingtalk.com/document#/org-dev-guide/obtain-access_token#topic-2609009
     */
    @Override
    public String getDingAccessToken(final String appkey, final String appsecret) {
        final String jsonStr = this.restTemplate.getForObject(DingDingServiceImpl.DING_OPEN_API_BASE_URL
                + String.format(DingDingServiceImpl.DING_GET_TOKEN_URL, appkey, appsecret), String.class);

        DingDingServiceImpl.log.info("request for {}\n{}",
                String.format(DingDingServiceImpl.DING_GET_TOKEN_URL, appkey, appsecret),
                jsonStr);

        final Map<String, Object> result = JsonUtils.jsonToMap(jsonStr);
        return result.containsKey("access_token") ? (String) result.get("access_token") : null;
    }

    /**
     * https://ding-doc.dingtalk.com/document#/org-dev-guide/userid#topic-1936806
     */
    @Override
    public String getDingUserIdByAuthCode(final String authCode) {
        final DingConfigDTO config = this.getDingConfig();
        if (null == config) {
            return null;
        }
        final String accessToken = this.getDingAccessToken(config.getAppKey(), config.getAppSecret());
        if (null == accessToken) {
            return null;
        }
        final String jsonStr = this.restTemplate.getForObject(DingDingServiceImpl.DING_OPEN_API_BASE_URL
                + String.format(DingDingServiceImpl.DING_GET_USER_INRO_URL, accessToken, authCode), String.class);

        DingDingServiceImpl.log.info("request for {}\n{}",
                String.format(DingDingServiceImpl.DING_GET_USER_INRO_URL, accessToken, authCode),
                jsonStr);

        final Map<String, Object> result = JsonUtils.jsonToMap(jsonStr);
        return result.containsKey("userid") ? (String) result.get("userid") : null;
    }

    @Override
    public DingUser bind(final String dingUserId, final String username) {
        final AuthUser authUser = this.authUserRepository.findByUsername(username);
        final DingUser dingUser = new DingUser();
        dingUser.setDingUserId(dingUserId);
        dingUser.setUser(authUser);
        this.dingUserRepository.save(dingUser);

        return dingUser;
    }

    @Override
    public String getDingUserIdBySystemUser(final String username) {
        final DingUser dingUser = this.dingUserRepository.findByUser_Username(username);
        if (null != dingUser) {
            return dingUser.getDingUserId();
        }
        return null;
    }

}
